#if defined(__IPHONE_3_0)

#include "Core.h"

#include <Xlib.h>
#include "RenderTypes.h"
#include "XWindow.h"

namespace p2
{

XWindow::XWindow(p2WindowCreateStruct const& cs) :
    Window(cs), _dpy(NULL), _win(0), _ctx(NULL), _wmDeleteWindow(0),
    _initialised(false)
{
}

XWindow::~XWindow()
{
    if (_initialised)
    {
        // cleanup
        ::glXDestroyContext(_dpy, _ctx);
        ::XDestroyWindow(_dpy, _win);
        ::XCloseDisplay(_dpy);
        _initialised = false;
    }
}

int32 XWindow::create()
{
    return create(NULL, _cs._name.c_str());
}

static int32 waitForMapNotify(Display *d, XEvent *e, XPointer arg)
{
    return (e->type == MapNotify) && (e->xmap.window == (Window) arg);
}

int32 XWindow::create(char const* className, char const* windowName)
{
    int32 attrib[] =
    {	GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
        GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None};
    XSetWindowAttributes attr;
    unsigned long mask;
    XVisualInfo *visinfo;

    if (_initialised)
    {
        PGLOG("Error: XWindow::create: window already initialised!\n");
        return -1;
    }
    _dpy = XOpenDisplay(className);
    if (!_dpy)
    {
        PGLOGF("Error: XWindow::create: couldn't open display %s\n", className);
        return -1;
    }

    Window root;
    int32 scrnum;
    scrnum = DefaultScreen( _dpy );
    root = RootWindow( _dpy, scrnum );

    visinfo = glXChooseVisual(_dpy, scrnum, attrib);
    if (!visinfo)
    {
        PGLOG(
            "Error: XWindow::create: couldn't get an RGB, double-buffered visual\n");
        return -1;
    }

    // create windowheight
    attr.background_pixel = 0;
    attr.border_pixel = 0;
    attr.colormap = XCreateColormap(_dpy, root, visinfo->visual, AllocNone);
    attr.event_mask = StructureNotifyMask | KeyPressMask
    | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;//StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;
    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
    _win = XCreateWindow(_dpy, root, _cs._winX, _cs._winY, _cs._winW,
        _cs._winH, 0, visinfo->depth, InputOutput, visinfo->visual, mask,
        &attr);

    // set hints and properties
    {
        ::XSizeHints sizehints;
        sizehints.x = _cs._winX;
        sizehints.y = _cs._winY;
        sizehints.width = _cs._winW;
        sizehints.height = _cs._winH;
        sizehints.flags = USSize | USPosition;
        XSetNormalHints(_dpy, _win, &sizehints);
        ::XSetStandardProperties(_dpy, _win, windowName, windowName, None,
            (char **) NULL, 0, &sizehints);
    }

    _ctx = glXCreateContext(_dpy, visinfo, NULL, True );
    if (!_ctx)
    {
        PGLOG("Error: GLWindow::create: glXCreateContext failed\n");
        return -1;
    }

    XFree(visinfo);

    // register interest in WM_DELETE_WINDOW
    _wmDeleteWindow = XInternAtom(_dpy, "WM_DELETE_WINDOW", False);
    if (_wmDeleteWindow == BadAlloc || _wmDeleteWindow == BadValue)
    {
        PGLOG("Error: GLWindow::create: XInternAtom failed\n");
        return -1;
    }
    if (!XSetWMProtocols(_dpy, _win, &_wmDeleteWindow, 1))
    {
        PGLOG("Error: GLWindow::create: XSetWMProtocols failed\n");
        return -1;
    }

    // guarantee that window is mapped before rendering
    ::XEvent event;
    ::glXMakeCurrent(_dpy, _win, _ctx);
    ::XMapWindow(_dpy, _win);
    ::XIfEvent(_dpy, &event, waitForMapNotify, (XPointer) _win);
    ::XSync(_dpy, 1);// flush output buffer

    // created
    _initialised = true;
    return 0;
}

int32 XWindow::processContinue() // return <=0 if quit received
{
    // REF: http://www.tcl.tk/man/tcl8.4/TkCmd/bind.htm

    if (!_initialised)
    {
        PGLOG("XWindow::processContinue: window not initialised!\n");
        return -1;
    }
    while (XPending(_dpy) > 0)
    {
        XEvent event;
        XNextEvent(_dpy, &event);
        switch (event.type)
        {
            case ClientMessage:
            if ((Atom) event.xclient.data.l[0] == _wmDeleteWindow)
            {
                PGLOG(
                    "Info: XWindow::processContinue: WM_DELETE_WINDOW received\n");
                return 1;
            }
            break;
            case KeyPress:
            {
                int32 code = XLookupKeysym(&event.xkey, 0);
                if (code == XK_Escape)
                {
                    char buffer[10] =
                    {	0};
                    XLookupString(&event.xkey, buffer, sizeof(buffer), NULL, NULL);
                    if (buffer[0] == 27)
                    {
                        PGLOG("Info: XWindow::processContinue: escape received\n");
                        return 0; // escape pressed
                    }
                }
                if (_cs._onKeyDown)
                {
                    _cs._onKeyDown(*this, code);
                }
                break;
            }
            case KeyRelease:
            {
                int32 code = XLookupKeysym(&event.xkey, 0);
                if (_cs._onKeyUp)
                {
                    _cs._onKeyUp(*this, code);
                }
                break;
            }
            case ButtonPress:
            {
                if (event.xbutton.button == Button3)
                {
                    if (_cs._onRButtonDown)
                    {
                        _cs._onRButtonDown(*this, event.xbutton.x, event.xbutton.y);
                    }
                }
                else if (event.xbutton.button == Button1)
                {
                    if (_cs._onLButtonDown)
                    {
                        _cs._onLButtonDown(*this, event.xbutton.x, event.xbutton.y);
                    }
                }
                break;
            }
            case ButtonRelease:
            {
                if (event.xbutton.button == Button3)
                {
                    if (_cs._onRButtonUp)
                    {
                        _cs._onRButtonUp(*this, event.xbutton.x, event.xbutton.y);
                    }
                }
                else if (event.xbutton.button == Button1)
                {
                    if (_cs._onLButtonUp)
                    {
                        _cs._onLButtonUp(*this, event.xbutton.x, event.xbutton.y);
                    }
                }
                break;
            }
        }
    }
    return 1;
}

void XWindow::swapBuffers() const
{
    ::glXSwapBuffers(_dpy, _win);
}

void XWindow::queryCursor(Point<int32>& position) const
{
    Window root, rootReturn, childReturn;
    int32 scrnum;
    scrnum = DefaultScreen( _dpy );
    root = RootWindow( _dpy, scrnum );

    Point<int32> rootPosition;
    uint32 state;

    XQueryPointer(_dpy, _win, &rootReturn, &childReturn, &rootPosition.x,
        &rootPosition.y, &position.x, &position.y, &state);
}

}

#endif  //#if defined(__IPHONE_3_0)
